import { AxesHelper, BufferGeometry, Color, DirectionalLight, Fog, GridHelper, HemisphereLight, Line, LineBasicMaterial, Mesh, MeshPhongMaterial, PCFSoftShadowMap, PerspectiveCamera, PlaneGeometry, Scene, sRGBEncoding, Vector3, WebGLRenderer } from "three";
import { CSS2DObject, CSS2DRenderer } from "three/examples/jsm/renderers/CSS2DRenderer";
import { CSSStyle, SceneDef } from "../const/ModelConst";
import { Line2 } from "three/examples/jsm/lines/Line2";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import TrackCameraCtrl from "../controls/TrackCameraCtrl";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";

export default class DesignScene implements IDispose {
    /** 场景 */
    private _scene: Scene;
    /** 摄像机:透视 */
    private _camera: PerspectiveCamera;
    /** 渲染 */
    private _render: WebGLRenderer;
    /** css2drender */
    private _css2dReder: CSS2DRenderer;
    /** 视口宽 */
    private _viewWidth: number;
    /** 视口高 */
    private _viewHeight: number;
    /** 控制器 */
    private _ctrls: TrackCameraCtrl;

    private _dirLight: DirectionalLight;
    private _effect: boolean;

    get scene(): Scene {
        return this._scene;
    }

    get camera(): any {
        return this._camera;
    }

    get render(): WebGLRenderer {
        return this._render;
    }

    get ctrls(): any {
        return this._ctrls;
    }

    get css2dRender(): CSS2DRenderer {
        return this._css2dReder;
    }

    constructor() {
        this.initData();
        this.createScene();
        this.createPCamera();
        this.createLight();
        this.createCSS2DRender();
        this.createRender();
        this.createControls();
    }

    private initData(): void {
        this._viewWidth = SceneDef.viewWidth;
        this._viewHeight = SceneDef.viewHeight;

        this._effect = false;
    }

    private createLabel(text: string, pos: Vector3, className:string): CSS2DObject {
        let div = document.createElement('div');
        div.className = className;
        div.textContent = text;

        let label = new CSS2DObject(div);
        label.position.set(pos.x, pos.y, pos.z);

        return label;
    }

    /** 创建透视相机 */
    private createPCamera(): void {
        // 透视
        this._camera = new PerspectiveCamera(50, this._viewWidth / this._viewHeight, SceneDef.near, SceneDef.far);
        this._camera.position.set(3000, 6000, 3000);
        this._camera.lookAt(new Vector3(0, 0, 0));

    }

    private createScene(): void {
        this._scene = new Scene();
        this._scene.background = new Color(0xa0a0a0);
        if (this._effect) {
            this._scene.fog = new Fog(0xa0a0a0, 1000, 50000);
        }
    }

    updateAxes(redp: Vector3[], greenp: Vector3[], bluep: Vector3[]): void {

        let geo: LineGeometry;
        let positions:number[];
        let matLine:LineMaterial;
        // 
        let reddata: Line2 = this._scene.getObjectByName('axes_red') as Line2;
        positions = [redp[0].x, redp[0].y, redp[0].z, redp[1].x, redp[1].y, redp[1].z];
        if (!reddata) {

            geo = new LineGeometry();
            geo.setPositions(positions);

            matLine = new LineMaterial({
                color: 0xff0000,
                linewidth: 2,
                dashed: false,
                depthTest: false,
                depthWrite:false,
                transparent:true,
            });

            matLine.resolution.set(this._viewWidth, this._viewHeight);
        
            reddata = new Line2(geo, matLine);
            reddata.name = 'axes_red';
            this._scene.add(reddata);
        }
        else {

            reddata.geometry.setPositions(positions);
            reddata.computeLineDistances();

        }

        let greendata = this._scene.getObjectByName('axes_green') as Line2;
        positions = [greenp[0].x, greenp[0].y, greenp[0].z, greenp[1].x, greenp[1].y, greenp[1].z];
        if (!greendata) {
            geo = new LineGeometry();
            geo.setPositions(positions);

            matLine = new LineMaterial({
                color: 0x00ff00,
                linewidth: 2,
                dashed: false,
                depthTest: false,
                depthWrite:false,
                transparent:true,
            });

            matLine.resolution.set(this._viewWidth, this._viewHeight);
        
            greendata = new Line2(geo, matLine);
            greendata.name = 'axes_green';
            this._scene.add(greendata);
        }
        else {
            greendata.geometry.setPositions(positions);
            greendata.computeLineDistances();
        }

        let bluedata = this._scene.getObjectByName('axes_blue') as Line2;
        positions = [bluep[0].x, bluep[0].y, bluep[0].z, bluep[1].x, bluep[1].y, bluep[1].z];
        if (!bluedata) {

            geo = new LineGeometry();
            geo.setPositions(positions);

            matLine = new LineMaterial({
                color: 0x0000ff,
                linewidth: 2,
                dashed: false,
                depthTest: false,
                depthWrite:false,
                transparent:true,
            });

            matLine.resolution.set(this._viewWidth, this._viewHeight);
        
            bluedata = new Line2(geo, matLine);
            bluedata.name = 'axes_blue';
            this._scene.add(bluedata);
        }
        else {
            bluedata.geometry.setPositions(positions);
            bluedata.computeLineDistances();
        }

        // 
        let redcenter = redp[1].clone().add(redp[0]).multiplyScalar(0.5);
        let greencenter = greenp[1].clone().add(greenp[0]).multiplyScalar(0.5);
        let bluecenter = bluep[1].clone().add(bluep[0]).multiplyScalar(0.5);

        let rcs2ddata = this._scene.getObjectByName('axes_length') as CSS2DObject;
        if (!rcs2ddata) {

            rcs2ddata = this.createLabel("长", redcenter, CSSStyle.LENGTH_TIPS);
            rcs2ddata.name = 'axes_length';
            this._scene.add(rcs2ddata);
        }
        else {
            rcs2ddata.position.set(redcenter.x, redcenter.y, redcenter.z);
        }

        let gcs2ddata = this._scene.getObjectByName('axes_width') as CSS2DObject;
        if (!gcs2ddata) {

            gcs2ddata = this.createLabel("宽", greencenter, CSSStyle.WIDTH_TIPS);
            gcs2ddata.name = 'axes_width';
            this._scene.add(gcs2ddata);
        }
        else {
            gcs2ddata.position.set(greencenter.x, greencenter.y, greencenter.z);
        }

        let bcs2ddata = this._scene.getObjectByName('axes_height') as CSS2DObject;
        if (!bcs2ddata) {

            bcs2ddata = this.createLabel("高", bluecenter, CSSStyle.HEIGHT_TIPS);
            bcs2ddata.name = 'axes_height';
            this._scene.add(bcs2ddata);
        }
        else {
            bcs2ddata.position.set(bluecenter.x, bluecenter.y, bluecenter.z);
        }
    }

    /** 添加光 */
    private createLight(): void {

        // 环境光，全局光照
        const hemiLight = new HemisphereLight(0xffffff, 0x444444);
        hemiLight.position.set(0, 10000, 0);
        this._scene.add(hemiLight);

        // 添加平行光,用来模拟太阳光
        this._dirLight = new DirectionalLight(0xffffff);
        this._dirLight.position.set(0, 4000, 5000);
        this._scene.add(this._dirLight);
    }

    private createRender(): void {
        this._render = new WebGLRenderer({
            precision: "highp", // 着色器精度:高
            antialias: true, // 锯齿
            // alpha: true, // canvas是否包含alpha (透明度)
            // logarithmicDepthBuffer: true, //是否使用对数深度缓存
        });
        // 设置尺寸
        this._render.setSize(this._viewWidth, this._viewHeight);
        // 设置设备的物理像素比
        this._render.setPixelRatio(this._viewWidth / this._viewHeight);
        this._render.outputEncoding = sRGBEncoding;
    }

    createCSS2DRender(): void {
        this._css2dReder = new CSS2DRenderer();
        this._css2dReder.setSize(this._viewWidth, this._viewHeight);
        this._css2dReder.domElement.style.position = 'absolute';
        this._css2dReder.domElement.style.top = '0px';
    }

    /** 添加控制器 */
    private createControls(): void {

        this._ctrls = new TrackCameraCtrl(this._camera, this._css2dReder.domElement, this._render.domElement, this._viewWidth, this._viewHeight);
        this._ctrls.minDistance = 10;
        this._ctrls.maxDistance = 100000;
        // this._ctrls.noPan = true

    }

    dispose(): void {

    }
}